/**
   Copyright 2008 Kirill Ignatiev

    This file is part of kerr-wavefronts.

    kerr-wavefronts is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    kerr-wavefronts is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with kerr-wavefronts.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <cstdio>
#include <map>
#include <list>
#include <vector>
#include <GL/gl.h>
#include <gsl/gsl_math.h>
#include <deque>
#include <utility>
#include "geodesic.h"

class ic_param {
public:
  ic_param(double _t0=0.0) : t0(_t0) { }
  virtual geodesic* geod(double j) = 0;

  double t0; // the time of the first point in this geodesic family
};

class line_param : public ic_param {
public:
  double r0;
  double length;
  line_param(double _r0, double _l) : r0(_r0), length(_l) { }
  geodesic* geod(double j);
};

class circle_param : public ic_param  {
public:
  double phi0;
  double r0;
  double angle;
  circle_param(double r0_, double angle_)
    : phi0(0), r0(r0_), angle(angle_) { }
  geodesic* geod(double j);
};

class kerr_line_param : public ic_param {
public:
  double r0, length;
  kerr_param p;
  kerr_line_param(double _r0, double _length, kerr_param _p)
  : r0(_r0), length(_length), p(_p) { }
  geodesic* geod(double j);
};

class kerr_circle_param : public ic_param  {
public:
  double phi0;
  double r0;
  double angle;
  kerr_param p;
  kerr_circle_param(double r0_, double angle_, kerr_param _p)
    : phi0(0), r0(r0_), angle(angle_), p(_p) { }
  geodesic* geod(double j);
};

struct point_t {
  double x, y, p;
};

class front_history {
public:
  static const int ndim = 3;
  int N;
  int size;
  double prev_time;
  double delay;
  typedef deque< pair<double, vector<double>* > > history_rep;
  typedef history_rep::const_iterator const_iterator;
  history_rep data;
  front_history(int n, double d) : N(n), prev_time(0), delay(d), size(0) { }

  void update(double time, const list<geodesic*>& geods,
              const list<double>& params);
  double current_time() { return data.begin()->first; }
};

class wavefront {
public:
  
  list<double> param;
  list<geodesic*> geodesics;
  ic_param* param_gen;
  front_history data;

  double colourmap[4];

  wavefront(ic_param* p1, const front_history& d);
  void evolve(double tmax);
  void evolve_once(double tmax);
  void render();
};

